Homework 8: Comparing and Analyzing Bipartite and Dynamic Networks¶
import altair as alt
import networkx as nx
import matplotlib.pyplot as plt
import nx_altair as nxa
import pandas as pd
# Note you will need a separate set of algorithms
from networkx.algorithms import bipartite
1. Creating the Bipartite Network, as well as calculating data from and visualizing it¶
B = bipartite.read_edgelist("out.brunson_revolution_revolution") # Create the Bipartite network
print(B)
Graph with 141 nodes and 160 edges
nx.is_connected(B)
True
top_nodes = {n for n, d in B.nodes(data=True) if d["bipartite"] == 0} # Create the top nodes group
bottom_nodes = set(B) - top_nodes # Create the Bottom nodes (Every node except the top nodes)
degree = nx.bipartite.degree_centrality(B, top_nodes) # Calculate Degree Centrality
betweenness = nx.bipartite.betweenness_centrality(B, top_nodes) # Calculate Betweenness Centrality
closeness = nx.bipartite.closeness_centrality(B, nodes=top_nodes) # Calculate Closeness Centrality
nx.set_node_attributes(B, degree, "degree_centrality") # Add Degree Centrality as a node attribute
nx.set_node_attributes(B, betweenness, "betweenness_centrality") # Add Betweenness Centrality as a node attribute
nx.set_node_attributes(B, closeness, "closeness_centrality") # Add Closeness Centrality as a node attribute
print(degree)
{'group_31': 0.6000000000000001, 'group_3': 0.2, 'group_85': 0.2, 'group_26': 0.2, 'group_107': 0.2, 'group_108': 0.2, 'group_61': 0.2, 'group_99': 0.2, 'group_66': 0.2, 'group_33': 0.2, 'group_70': 0.2, 'group_116': 0.2, 'group_73': 0.2, 'group_29': 0.2, 'group_8': 0.4, 'group_132': 0.2, 'group_94': 0.2, 'group_71': 0.2, 'group_104': 0.2, 'group_117': 0.2, 'group_42': 0.2, 'group_98': 0.2, 'group_48': 0.2, 'group_64': 0.2, 'group_135': 0.2, 'group_11': 0.2, 'group_62': 0.2, 'group_122': 0.2, 'group_127': 0.2, 'group_43': 0.2, 'group_80': 0.2, 'group_119': 0.2, 'group_100': 0.2, 'group_60': 0.2, 'group_69': 0.2, 'group_45': 0.4, 'group_9': 0.2, 'group_56': 0.2, 'group_77': 0.2, 'group_67': 0.2, 'group_20': 0.2, 'group_16': 0.2, 'group_87': 0.2, 'group_79': 0.2, 'group_130': 0.2, 'group_15': 0.2, 'group_103': 0.2, 'group_125': 0.4, 'group_57': 0.2, 'group_38': 0.4, 'group_39': 0.2, 'group_111': 0.2, 'group_136': 0.4, 'group_115': 0.2, 'group_65': 0.2, 'group_93': 0.2, 'group_134': 0.2, 'group_21': 0.2, 'group_75': 0.2, 'group_83': 0.2, 'group_120': 0.2, 'group_124': 0.2, 'group_76': 0.2, 'group_133': 0.2, 'group_110': 0.2, 'group_74': 0.2, 'group_52': 0.2, 'group_34': 0.2, 'group_81': 0.2, 'group_123': 0.2, 'group_12': 0.2, 'group_49': 0.2, 'group_44': 0.2, 'group_102': 0.2, 'group_37': 0.2, 'group_106': 0.6000000000000001, 'group_82': 0.2, 'group_4': 0.4, 'group_19': 0.2, 'group_28': 0.2, 'group_35': 0.2, 'group_1': 0.4, 'group_17': 0.2, 'group_101': 0.2, 'group_46': 0.2, 'group_112': 0.2, 'group_131': 0.2, 'group_23': 0.2, 'group_97': 0.2, 'group_84': 0.4, 'group_10': 0.4, 'group_22': 0.2, 'group_129': 0.4, 'group_113': 0.2, 'group_90': 0.2, 'group_6': 0.2, 'group_41': 0.4, 'group_53': 0.2, 'group_58': 0.2, 'group_55': 0.4, 'group_24': 0.2, 'group_95': 0.2, 'group_68': 0.2, 'group_118': 0.2, 'group_89': 0.4, 'group_5': 0.2, 'group_126': 0.8, 'group_86': 0.2, 'group_63': 0.2, 'group_96': 0.2, 'group_27': 0.4, 'group_36': 0.2, 'group_47': 0.2, 'group_91': 0.2, 'group_92': 0.2, 'group_30': 0.2, 'group_128': 0.2, 'group_2': 0.6000000000000001, 'group_50': 0.2, 'group_59': 0.2, 'group_78': 0.2, 'group_72': 0.2, 'group_105': 0.4, 'group_54': 0.2, 'group_109': 0.2, 'group_40': 0.2, 'group_18': 0.2, 'group_14': 0.2, 'group_88': 0.2, 'group_121': 0.2, 'group_32': 0.2, 'group_7': 0.2, 'group_25': 0.2, 'group_114': 0.2, 'group_51': 0.2, 'group_13': 0.2, '3': 0.15441176470588236, '2': 0.125, '4': 0.3897058823529412, '5': 0.07352941176470588, '1': 0.4338235294117647}
print(betweenness)
{'group_1': 0.01682618254068547, '1': 0.6147249520417205, '2': 0.15689321105095708, 'group_2': 0.030621735860535515, '3': 0.16524088215037874, 'group_3': 0.0, 'group_4': 0.009673225817420573, 'group_5': 0.0, '4': 0.5848326892339956, 'group_6': 0.0, '5': 0.08266771442280396, 'group_7': 0.0, 'group_8': 0.009673225817420573, 'group_9': 0.0, 'group_10': 0.02172958033572083, 'group_11': 0.0, 'group_12': 0.0, 'group_13': 0.0, 'group_14': 0.0, 'group_15': 0.0, 'group_16': 0.0, 'group_17': 0.0, 'group_18': 0.0, 'group_19': 0.0, 'group_20': 0.0, 'group_21': 0.0, 'group_22': 0.0, 'group_23': 0.0, 'group_24': 0.0, 'group_25': 0.0, 'group_26': 0.0, 'group_27': 0.02172958033572083, 'group_28': 0.0, 'group_29': 0.0, 'group_30': 0.0, 'group_31': 0.030621735860535515, 'group_32': 0.0, 'group_33': 0.0, 'group_34': 0.0, 'group_35': 0.0, 'group_36': 0.0, 'group_37': 0.0, 'group_38': 0.024231279399237016, 'group_39': 0.0, 'group_40': 0.0, 'group_41': 0.009673225817420573, 'group_42': 0.0, 'group_43': 0.0, 'group_44': 0.0, 'group_45': 0.02172958033572083, 'group_46': 0.0, 'group_47': 0.0, 'group_48': 0.0, 'group_49': 0.0, 'group_50': 0.0, 'group_51': 0.0, 'group_52': 0.0, 'group_53': 0.0, 'group_54': 0.0, 'group_55': 0.009673225817420573, 'group_56': 0.0, 'group_57': 0.0, 'group_58': 0.0, 'group_59': 0.0, 'group_60': 0.0, 'group_61': 0.0, 'group_62': 0.0, 'group_63': 0.0, 'group_64': 0.0, 'group_65': 0.0, 'group_66': 0.0, 'group_67': 0.0, 'group_68': 0.0, 'group_69': 0.0, 'group_70': 0.0, 'group_71': 0.0, 'group_72': 0.0, 'group_73': 0.0, 'group_74': 0.0, 'group_75': 0.0, 'group_76': 0.0, 'group_77': 0.0, 'group_78': 0.0, 'group_79': 0.0, 'group_80': 0.0, 'group_81': 0.0, 'group_82': 0.0, 'group_83': 0.0, 'group_84': 0.009673225817420573, 'group_85': 0.0, 'group_86': 0.0, 'group_87': 0.0, 'group_88': 0.0, 'group_89': 0.004122327502429542, 'group_90': 0.0, 'group_91': 0.0, 'group_92': 0.0, 'group_93': 0.0, 'group_94': 0.0, 'group_95': 0.0, 'group_96': 0.0, 'group_97': 0.0, 'group_98': 0.0, 'group_99': 0.0, 'group_100': 0.0, 'group_101': 0.0, 'group_102': 0.0, 'group_103': 0.0, 'group_104': 0.0, 'group_105': 0.004122327502429542, 'group_106': 0.17395708628062748, 'group_107': 0.0, 'group_108': 0.0, 'group_109': 0.0, 'group_110': 0.0, 'group_111': 0.0, 'group_112': 0.0, 'group_113': 0.0, 'group_114': 0.0, 'group_115': 0.0, 'group_116': 0.0, 'group_117': 0.0, 'group_118': 0.0, 'group_119': 0.0, 'group_120': 0.0, 'group_121': 0.0, 'group_122': 0.0, 'group_123': 0.0, 'group_124': 0.0, 'group_125': 0.11242883462908994, 'group_126': 0.2762723804196298, 'group_127': 0.0, 'group_128': 0.0, 'group_129': 0.024231279399237016, 'group_130': 0.0, 'group_131': 0.0, 'group_132': 0.0, 'group_133': 0.0, 'group_134': 0.0, 'group_135': 0.0, 'group_136': 0.009673225817420573}
print(closeness)
{'group_31': 0.7069408740359897, 'group_3': 0.6292906178489702, 'group_85': 0.6124721603563474, 'group_26': 0.6292906178489702, 'group_107': 0.6292906178489702, 'group_108': 0.6124721603563474, 'group_61': 0.6124721603563474, 'group_99': 0.5238095238095238, 'group_66': 0.6124721603563474, 'group_33': 0.6124721603563474, 'group_70': 0.6292906178489702, 'group_116': 0.6292906178489702, 'group_73': 0.6292906178489702, 'group_29': 0.6124721603563474, 'group_8': 0.6690997566909975, 'group_132': 0.6124721603563474, 'group_94': 0.6292906178489702, 'group_71': 0.6292906178489702, 'group_104': 0.6124721603563474, 'group_117': 0.6292906178489702, 'group_42': 0.6124721603563474, 'group_98': 0.5159474671669794, 'group_48': 0.4716981132075472, 'group_64': 0.6292906178489702, 'group_135': 0.6292906178489702, 'group_11': 0.6124721603563474, 'group_62': 0.6292906178489702, 'group_122': 0.6292906178489702, 'group_127': 0.6124721603563474, 'group_43': 0.5159474671669794, 'group_80': 0.6292906178489702, 'group_119': 0.6292906178489702, 'group_100': 0.6124721603563474, 'group_60': 0.5238095238095238, 'group_69': 0.6124721603563474, 'group_45': 0.6532066508313539, 'group_9': 0.6124721603563474, 'group_56': 0.5238095238095238, 'group_77': 0.5238095238095238, 'group_67': 0.6124721603563474, 'group_20': 0.6124721603563474, 'group_16': 0.6124721603563474, 'group_87': 0.6124721603563474, 'group_79': 0.6124721603563474, 'group_130': 0.5238095238095238, 'group_15': 0.5238095238095238, 'group_103': 0.6292906178489702, 'group_125': 0.8208955223880597, 'group_57': 0.6124721603563474, 'group_38': 0.6380510440835266, 'group_39': 0.5238095238095238, 'group_111': 0.6124721603563474, 'group_136': 0.6690997566909975, 'group_115': 0.6292906178489702, 'group_65': 0.6292906178489702, 'group_93': 0.6292906178489702, 'group_134': 0.5159474671669794, 'group_21': 0.6292906178489702, 'group_75': 0.6124721603563474, 'group_83': 0.6124721603563474, 'group_120': 0.6292906178489702, 'group_124': 0.5159474671669794, 'group_76': 0.6292906178489702, 'group_133': 0.6124721603563474, 'group_110': 0.6292906178489702, 'group_74': 0.5159474671669794, 'group_52': 0.6124721603563474, 'group_34': 0.6292906178489702, 'group_81': 0.6124721603563474, 'group_123': 0.4716981132075472, 'group_12': 0.6124721603563474, 'group_49': 0.6124721603563474, 'group_44': 0.6124721603563474, 'group_102': 0.6292906178489702, 'group_37': 0.5159474671669794, 'group_106': 0.889967637540453, 'group_82': 0.6292906178489702, 'group_4': 0.6690997566909975, 'group_19': 0.6124721603563474, 'group_28': 0.6292906178489702, 'group_35': 0.6292906178489702, 'group_1': 0.6690997566909975, 'group_17': 0.6292906178489702, 'group_101': 0.5238095238095238, 'group_46': 0.6292906178489702, 'group_112': 0.4716981132075472, 'group_131': 0.6292906178489702, 'group_23': 0.6124721603563474, 'group_97': 0.6124721603563474, 'group_84': 0.6690997566909975, 'group_10': 0.6532066508313539, 'group_22': 0.6124721603563474, 'group_129': 0.6380510440835266, 'group_113': 0.6124721603563474, 'group_90': 0.6124721603563474, 'group_6': 0.4716981132075472, 'group_41': 0.6690997566909975, 'group_53': 0.6292906178489702, 'group_58': 0.5159474671669794, 'group_55': 0.6690997566909975, 'group_24': 0.6292906178489702, 'group_95': 0.6124721603563474, 'group_68': 0.6124721603563474, 'group_118': 0.5238095238095238, 'group_89': 0.5511022044088176, 'group_5': 0.6124721603563474, 'group_126': 0.9581881533101045, 'group_86': 0.6292906178489702, 'group_63': 0.6124721603563474, 'group_96': 0.6292906178489702, 'group_27': 0.6532066508313539, 'group_36': 0.5159474671669794, 'group_47': 0.6124721603563474, 'group_91': 0.6292906178489702, 'group_92': 0.6292906178489702, 'group_30': 0.6292906178489702, 'group_128': 0.6124721603563474, 'group_2': 0.7069408740359897, 'group_50': 0.5159474671669794, 'group_59': 0.6292906178489702, 'group_78': 0.6124721603563474, 'group_72': 0.6124721603563474, 'group_105': 0.5511022044088176, 'group_54': 0.6124721603563474, 'group_109': 0.6292906178489702, 'group_40': 0.5159474671669794, 'group_18': 0.6124721603563474, 'group_14': 0.5238095238095238, 'group_88': 0.6124721603563474, 'group_121': 0.6124721603563474, 'group_32': 0.4716981132075472, 'group_7': 0.6292906178489702, 'group_25': 0.6292906178489702, 'group_114': 0.6292906178489702, 'group_51': 0.6124721603563474, 'group_13': 0.6292906178489702, '3': 0.37305699481865284, '2': 0.36548223350253806, '4': 0.4645161290322581, '5': 0.32432432432432434, '1': 0.48322147651006714}
nx.write_gml(B, "brunson_revolution_revolution.gml", stringizer=None) # Export the Network into a .gml file
pos = nx.bipartite_layout(B, top_nodes)
# Makes sure that the layout in all three nx_altair visualizations is a bipartite layout, where the top nodes are on the right and the bottom nodes are on the left
alt.data_transformers.disable_max_rows()
viz_degree = nxa.draw_networkx(B,
pos=pos,
node_size='degree_centrality',
node_color='bipartite',
node_tooltip=['degree_centrality']
)
viz_degree.interactive()
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False) C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False)
alt.data_transformers.disable_max_rows()
viz_between = nxa.draw_networkx(B,
pos=pos,
node_size='betweenness_centrality',
node_color='bipartite',
node_tooltip=['betweenness_centrality']
)
viz_between.interactive()
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False) C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False)
alt.data_transformers.disable_max_rows()
viz_close = nxa.draw_networkx(B,
pos=pos,
node_size='closeness_centrality',
node_color='bipartite',
node_tooltip=['closeness_centrality']
)
viz_close.interactive()
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False) C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False)
After calculating the data, I determined the correlation between American Revolutionary figures and the number of “groups” they belonged to. I found that high degree centrality was determined by the number of specific groups a particular person was a part of and/or the number of people within a particular group. High betweenness centrality was determined by the path of “groups”/nodes that a particular person must follow/pass through in order to arrive at their final destination (group). High closeness centrality value was determined by the average shortest path length between any two nodes (people and groups)..
After analyzing the data, I learned that the more important and well known figures in the American Revolution have higher centrality values. I determined after closely examining person/figure 126. Figure 126 had the highest centrality value. This means he has been a part of multiple groups and interacted with the highest number of people.
2. Transforming the Bipartite Network into a Unipartite network (based on the people), as well as visualizing and analyzing it¶
U = bipartite.weighted_projected_graph(B, top_nodes) # Transform the Bipartite Network into a Unipartite network, where the nodes are the people
print(U)
Graph with 136 nodes and 3420 edges
pos_uni = nx.spring_layout(U) # Positions the nodes into a spring layout for future use
viz_unipartite = nxa.draw_networkx(U,
pos=pos_uni
)
viz_unipartite.interactive() # Visualize the Unipartite Network in nx_altair
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False) C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version. Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``. col = df[col_name].apply(to_list_if_array, convert_dtype=False)
By transforming the data into a unipartite graph, the visualization creates a better picture of the clustering of nodes based on which group individuals are a part of. Rather than having nodes on either side of the graph, individuals are represented as large red nodes/circles assembled together in large “clumps” that designate which group they belong to. It is easier to analyze which groups have more participants, and vice versa. Unfortunately, while the groupings are large or small, it is impossible to know the difference between groups, as it is no longer a bipartite layout. In my opinion, this visualization may be aesthetically pleasing, it is not a useful way of accurately representing the data.
3. Starting to work with Dynamic Networks, starting with importing one into Gephi and analyzing the Network over time¶
Here is the Network where the network start to rapidly grow in terms of connections
Here is the network when the most amount of edges are visibile (1656)
Here is the Network at the end of the timeline, where there is only one real edge
The time period spanned from 1550 - 1760. During this time period, most relationships were active in the year 1656. I was able to determine this by carefully analyzing the time line box using the context window to find the number of edges/relationships active at different points of time. There were 231 edges/relationships in the year 1656 (the maximum number of visible edges). This makes sense because 1656 is somewhere in the middle of the time period, allowing for relationships to grow and decline over time. Various factors could play a role in the decline of relationships, including people moving away from one another, disagreements, illness, death, etc.
4. Working with the Dynamic Network in Jupyter Notebook, and analyzing it during specific Time periods¶
nodes = pd.read_csv("quaker_nodelist.csv")
q = pd.read_csv("quaker_edgelist.csv")
all_nodes = nodes.name.to_list()
intervals = range(q["Start Year"].min(),q["End Year"].max(),20)
new_edges = []
for n,row in q.iterrows():
for i,x in enumerate(intervals):
try:
if row["Start Year"] <= x <= row["End Year"]:
new_edges.append({'i': all_nodes.index(row['Source']), 'j': all_nodes.index(row['Target']), 't': i})
except IndexError:
if row["Start Year"] <= x <= q["End Year"].max():
new_edges.append({'i': row['Source ID'], 'j': row['Target ID'], 't': i})
new_df = pd.DataFrame(new_edges)
new_df
| i | j | t | |
|---|---|---|---|
| 0 | 122 | 28 | 4 |
| 1 | 122 | 28 | 5 |
| 2 | 122 | 167 | 4 |
| 3 | 122 | 167 | 5 |
| 4 | 122 | 127 | 4 |
| ... | ... | ... | ... |
| 939 | 163 | 74 | 5 |
| 940 | 163 | 74 | 6 |
| 941 | 74 | 2 | 5 |
| 942 | 74 | 2 | 6 |
| 943 | 74 | 2 | 7 |
944 rows × 3 columns
from teneto import TemporalNetwork
tnet = TemporalNetwork(from_df=new_df)
tnet.network
| i | j | t | |
|---|---|---|---|
| 0 | 122 | 28 | 4 |
| 1 | 122 | 28 | 5 |
| 2 | 122 | 167 | 4 |
| 3 | 122 | 167 | 5 |
| 4 | 122 | 127 | 4 |
| ... | ... | ... | ... |
| 939 | 163 | 74 | 5 |
| 940 | 163 | 74 | 6 |
| 941 | 74 | 2 | 5 |
| 942 | 74 | 2 | 6 |
| 943 | 74 | 2 | 7 |
944 rows × 3 columns
from teneto.networkmeasures import * # imports various functions to make the calculations possible
tdc=temporal_degree_centrality(tnet,calc='overtime') #calculate temporal degree centrality
tdc
array([ 0., 4., 0., 0., 8., 16., 0., 0., 1., 0., 6., 0., 0.,
14., 0., 0., 18., 10., 0., 10., 0., 2., 0., 0., 3., 2.,
0., 0., 0., 0., 24., 0., 4., 0., 0., 3., 0., 8., 4.,
14., 0., 14., 12., 18., 6., 3., 1., 7., 0., 6., 0., 1.,
4., 0., 0., 0., 2., 0., 0., 0., 0., 0., 30., 0., 4.,
0., 0., 41., 3., 3., 0., 2., 2., 0., 20., 15., 22., 0.,
1., 0., 2., 4., 0., 22., 1., 0., 0., 0., 0., 0., 8.,
0., 0., 0., 2., 0., 3., 3., 0., 4., 3., 0., 4., 2.,
0., 14., 0., 6., 6., 0., 6., 3., 4., 9., 0., 0., 3.,
40., 3., 3., 0., 10., 41., 2., 4., 1., 0., 8., 3., 11.,
0., 3., 22., 0., 0., 5., 0., 2., 0., 0., 0., 3., 1.,
4., 0., 3., 1., 8., 0., 4., 2., 0., 7., 0., 0., 0.,
6., 4., 0., 3., 3., 2., 0., 2., 6., 0., 6., 2., 0.,
4., 3., 1., 20., 0., 2., 6., 3., 0., 0., 4., 0., 73.,
0., 94., 3., 20., 1., 6., 0., 0., 2., 0.])
fluctuability(tnet,calc='overtime') #calculate fluctuability
0.4182692307692308
topological_overlap(tnet,calc='overtime') #calculate topological overlap
C:\Users\ericg\anaconda3\Lib\site-packages\teneto\networkmeasures\topological_overlap.py:143: RuntimeWarning: invalid value encountered in divide topo_overlap = numerator / denominator
0.08648296881117057
len(nodes)
245
Temporal degree centrality describes the sum of all the possible connections/relationships with other individuals that person had over a time period. After analyzing the data, I was able to determine that half of the individuals within the dataset had no relationships with one another during the entire time period. However, the other half of the individuals within the dataset had either a few or many relationships. Meaning, you either knew a lot of people or very few.
Fluctuability describes the variation of edges/relationships over time. For example, an individual could begin the time period with a small number of relationships, add more as time goes on, and possibly lose a few relationships due to a various number of factors (including death). Based on my calculations, the network has a fluctuability value of 0.42. There is some variation of relationships over the course of the time period; however, one can interpret that most people did not add many relationships over time due to the small fluctuability value.
Topological overlap describes the stability of edges/relationships remaining over time. This means that an individual would keep the same number of relationships over a course of time, losing very few if any, while possibly gaining more. The topological overlap value of this network was 0.08. One can interpret this as a weak topological overlap, meaning that individuals did not maintain strong relationships among one another. This could be due to many different circumstances, including health, people moving away from one another, or disagreements that individuals may have had that severed their relationships.
The network was not very consistent over time, as its topological overlap value was very small at 0.08.
5. Plotting the Temporal Network using Teneto¶
import teneto as teneto
from teneto import plot
fig,ax = plt.subplots(figsize=(25,100))
ax = plt.subplot(1,1,1)
tnet.plot('slice_plot', ax=ax, cmap='Set2')
<Axes: xlabel='Time'>
The slice plot represents historical figures from the Quaker dataset. The nodes represent actual people. Edges represent the relationship between two Quakers, The plot is separated into 11 different time periods, called epochs. The x axis (horizontal lines) represent the 11 different time periods (ranging from the years 1526 - 1775). Unfortunately, due to the limitations of the Teneto library, it is impossible to distinguish which periods of time correlate to the 11 separate columns.
The y axis (vertical lines) represent individual Quakers (people) that lived during the 11 different epochs. Again, it is impossible to distinguish which nodes (circles) correlate to individuals due to the Teneto library’s limitation. For our purposes, we will not dwell on the individual names. Rather, we will focus on the relationships between these individuals during the 11 various epochs.
The nodes(circles) represented at each intersection of the x/y represents a specific individual that lived during that specific time period. Note: A side effect of the Teneto library represents different colored nodes throughout the slice plot. This is of no significant importance. All nodes, regardless of color, represent a person.
The arcs/lines between nodes represent some type of relationship between two Quakers that lived during a specific time period.
A quick glance shows that the number of active relationships between the Quakers rapidly grew during the first 6 epochs and slowly declined over the last 5 epochs. The 6th epoch was the peak (maximum number of active relationships) over this time span.
This plot was different from the Gephi Temporal network in that multiple time periods (epochs) were displayed on the plot so that viewers can easily distinguish the number of active relationships during a time period and watch as they changed (grew and declined). The Gephi Temporal network showed nodes and active relationships of only one time period per graph. This means that the viewer would have to look at different graphs and then compare and contrast them with each other, a much less efficient and more confusing way to analyze the data.